
#include "asr_rtl8763bo_port.h"

#if USE_LV_BLUETOOTH != 0


#ifndef AUDIO_PLAY_NORMAL

#include "dataTrans_queue.h"
#include "lvgl/src/lv_misc/lv_fs.h"
#include "test_pcm.h"

#define PCM_TX_TRIGGER_TIMEOUT    (20)  /// ms
#define PCM_RX_TRIGGER_TIMEOUT    (20)  /// ms

#define PCM_SAMPLE_RATE    16000
#define PCM_BITWIDTH       16
#define PCM_CHANNELS       1

#define PCM_TX_SEND_BYTE   ((PCM_SAMPLE_RATE*PCM_BITWIDTH*PCM_CHANNELS/1000/8)*PCM_TX_TRIGGER_TIMEOUT)  // 640 bytes
#define PCM_RX_RECV_BYTE   ((PCM_SAMPLE_RATE*PCM_BITWIDTH*PCM_CHANNELS/1000/8)*PCM_RX_TRIGGER_TIMEOUT)  // 640 bytes

#define TEST_PCM_TX_RX_TASK_PRIORITY                30
#define TEST_PCM_TX_RX_TASK_STACK_SIZE              8192
#define TEST_PCM_TX_RX_TASK_MSGQ_SIZE               0x30

#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_FILE)
#define TX_LOCAL_BUFFER_SIZE  (512 * 4)
#else
#define TX_LOCAL_BUFFER_SIZE  PCM_TX_SEND_BYTE
#endif

#define RX_LOCAL_BUFFER_SIZE  PCM_RX_RECV_BYTE

static TASK_HANDLE * test_pcm_tx_rx_task_handle = NULL;
static uint8_t * tx_local_buffer = NULL;
static uint8_t * rx_local_buffer = NULL;

static void * g_PCMTxTimer = NULL;
static void * g_PCMRxTimer = NULL;

static uint32_t g_pcm_file_offset = 0;
static lv_fs_file_t g_pcm_file_fd;

static uint32_t g_pcm_file_size = 0;

extern void bbpro_send_pcm_data(short * pData, unsigned short Length);
extern void bbpro_receive_pcm_data(short * pData, unsigned short Length);
extern rbuf_t * g_pcm_tx_rbuf;

static void test_20ms_tx_trigger(uint32_t arg)
{
    UI_EVENT ev = {0};
    BOOL status;

#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_BUFFER)
    memset((VOID *)&ev, 0x0, sizeof(UI_EVENT));
    ev.nEventId = 0x1234;
    status = uos_send_event(test_pcm_tx_rx_task_handle, &ev, UOS_WAIT_FOREVER, UOS_EVENT_PRI_NORMAL);
    ASSERT(status == TRUE);
#endif

#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_FILE)
    {
        int available_size = 0;

        // check available free space
        if((available_size = bbpro_rbuf_available(g_pcm_tx_rbuf)) >= TX_LOCAL_BUFFER_SIZE) {
            memset((VOID *)&ev, 0x0, sizeof(UI_EVENT));
            ev.nEventId = 0xabcd;
            status = uos_send_event(test_pcm_tx_rx_task_handle, &ev, UOS_WAIT_FOREVER, UOS_EVENT_PRI_NORMAL);
            ASSERT(status == TRUE);
        }
    }
#endif

}

static void test_start_20ms_tx_timer(void)
{
    MODLOGD("%s, %x", __func__, g_PCMTxTimer);
    if(g_PCMTxTimer == NULL) {
        uos_timer_create(&g_PCMTxTimer);
        uos_timer_start(g_PCMTxTimer, MS_TO_TICKS(PCM_TX_TRIGGER_TIMEOUT), MS_TO_TICKS(PCM_TX_TRIGGER_TIMEOUT), test_20ms_tx_trigger, (uint32_t)0);
    }
}

static void test_stop_20ms_tx_timer(void)
{
    MODLOGD("%s, %x", __func__, g_PCMTxTimer);
    if(g_PCMTxTimer != NULL) {
        uos_timer_stop(g_PCMTxTimer);
        uos_timer_delete(g_PCMTxTimer);
        g_PCMTxTimer = NULL;
    }
}

static void test_20ms_rx_trigger(uint32_t arg)
{
    UI_EVENT ev = {0};
    BOOL status;

    memset((VOID *)&ev, 0x0, sizeof(UI_EVENT));

    ev.nEventId = 0x5678;
    status = uos_send_event(test_pcm_tx_rx_task_handle, &ev, UOS_WAIT_FOREVER, UOS_EVENT_PRI_NORMAL);
    ASSERT(status == TRUE);

}

static void test_start_20ms_rx_timer(void)
{
    MODLOGD("%s, %x", __func__, g_PCMRxTimer);
    if(g_PCMRxTimer == NULL) {
        uos_timer_create(&g_PCMRxTimer);
        uos_timer_start(g_PCMRxTimer, MS_TO_TICKS(PCM_RX_TRIGGER_TIMEOUT), MS_TO_TICKS(PCM_RX_TRIGGER_TIMEOUT), test_20ms_rx_trigger, (uint32_t)0);
    }
}

static void test_stop_20ms_rx_timer(void)
{
    MODLOGD("%s, %x", __func__, g_PCMRxTimer);
    if(g_PCMRxTimer != NULL) {
        uos_timer_stop(g_PCMRxTimer);
        uos_timer_delete(g_PCMRxTimer);
        g_PCMRxTimer = NULL;
    }
}

static void test_play_local_file_start(void)
{
    const char * file_16000 = "C:/avdtp_16000.pcm";
    const char * file_name = file_16000;
    int read_size = 0, used_size = 0, total_size;
    int watermark, real_read, real_write;
    int ret = 0;
    lv_fs_res_t res;

    MODLOGD("%s", __func__);

    if(g_pcm_tx_rbuf == NULL) {
        MODLOGE("tx rbuf empty");
        //ASSERT(0);
        return;
    }

    bbpro_rbuf_clear(g_pcm_tx_rbuf);

    total_size = bbpro_rbuf_size(g_pcm_tx_rbuf);
    if(total_size == 0) {
        MODLOGE("tx rbuf size 0");
        //ASSERT(0);
        return;
    }

    watermark = total_size / 2;

    MODLOGD("tx_rbuf size: %d(0x%x), watermark size: %d(0x%x)", total_size, total_size, watermark, watermark);

    res = lv_fs_open(&g_pcm_file_fd, file_name, LV_FS_MODE_RD);
    if(res != LV_FS_RES_OK) {
        MODLOGE("open file %s failed\r\n", file_name);
        //ASSERT(0);
        return;
    }

    res = lv_fs_size(&g_pcm_file_fd, &g_pcm_file_size);
    if(ret != LV_FS_RES_OK) {
        MODLOGE("pcm file size 0");
        //ASSERT(0);
        return;
    }

    MODLOGD("pcm file size: %d(0x%x)", g_pcm_file_size, g_pcm_file_size);

    g_pcm_file_offset = 0;

    /* read multiple packet */
    while(1) {
        if((used_size = bbpro_rbuf_used(g_pcm_tx_rbuf)) >= watermark) {
            MODLOGD("read done");
            break;
        }

        read_size = (watermark - used_size) < TX_LOCAL_BUFFER_SIZE ? (watermark - used_size) : TX_LOCAL_BUFFER_SIZE;
        if(read_size > (g_pcm_file_size - g_pcm_file_offset))
            read_size = (g_pcm_file_size - g_pcm_file_offset);

        res = lv_fs_seek(&g_pcm_file_fd, g_pcm_file_offset);
        if(res != LV_FS_RES_OK) {
            MODLOGE("seek failed, %d(0x%x)", g_pcm_file_offset, g_pcm_file_offset);
            break;
        }
        res = lv_fs_read(&g_pcm_file_fd, (void *)tx_local_buffer, read_size, (uint32_t *)&real_read);
        if(res != LV_FS_RES_OK) {
            MODLOGE("read failed, %d(0x%x)", read_size, read_size);
            break;
        }
        real_write = bbpro_rbuf_write(g_pcm_tx_rbuf, tx_local_buffer, read_size);
        g_pcm_file_offset = g_pcm_file_offset + real_write;
        if(g_pcm_file_offset >= g_pcm_file_size)
            g_pcm_file_offset = 0;

        MODLOGD("offset: 0x%x", g_pcm_file_offset);
    }
}

static void test_play_local_file_read(void)
{
    int real_write, real_read;
    lv_fs_res_t res;

    // check available free space
    if((bbpro_rbuf_available(g_pcm_tx_rbuf)) >= TX_LOCAL_BUFFER_SIZE) {
        if(g_pcm_file_offset + TX_LOCAL_BUFFER_SIZE > g_pcm_file_size)
            g_pcm_file_offset = 0;

        res = lv_fs_seek(&g_pcm_file_fd, g_pcm_file_offset);
        if(res != LV_FS_RES_OK) {
            MODLOGE("seek failed, %d(0x%x)", g_pcm_file_offset, g_pcm_file_offset);
            return;
        }

        res = lv_fs_read(&g_pcm_file_fd, (void *)tx_local_buffer, TX_LOCAL_BUFFER_SIZE, (uint32_t *)&real_read);
        if(res != LV_FS_RES_OK) {
            MODLOGE("read failed, %d", TX_LOCAL_BUFFER_SIZE);
            return;
        }

        real_write = bbpro_rbuf_write(g_pcm_tx_rbuf, tx_local_buffer, TX_LOCAL_BUFFER_SIZE);
        g_pcm_file_offset = g_pcm_file_offset + real_write;

        ///MODLOGD("offset: 0x%x", g_pcm_file_offset);
    }

}

static void test_play_local_file_stop(void)
{
    MODLOGD("%s", __func__);

    lv_fs_close(&g_pcm_file_fd);
}

static void test_pcm_tx_rx_task(void * p_param)
{
    UI_EVENT ev;
    uint32_t i;

    MODLOGD("%s ++", __func__);

    uos_sleep(40);

#if (AUDIO_TX_SELECT != AUDIO_TX_AUDIOHAL)
#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_BUFFER)
    // prepare tx data
    if(tx_local_buffer) {
        for(i = 0; i < PCM_TX_SEND_BYTE; i++)
            tx_local_buffer[i] = i;
    }
#endif
    test_start_20ms_tx_timer();  // both AUDIO_TX_LOCAL_BUFFER and AUDIO_TX_LOCAL_FILE need it
#endif

    uos_sleep(10);

#if (AUDIO_RX_SELECT == AUDIO_RX_LOCAL_BUFFER)
    test_start_20ms_rx_timer();
#endif

    while(true) {
        memset(&ev, 0, sizeof(ev));
        if(uos_wait_event(test_pcm_tx_rx_task_handle, &ev, UOS_WAIT_FOREVER) == true) {
            switch(ev.nEventId) {
#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_BUFFER)
                case 0x1234:
                    bbpro_send_pcm_data((short *)tx_local_buffer, PCM_TX_SEND_BYTE);
                    break;
#endif
#if (AUDIO_RX_SELECT == AUDIO_RX_LOCAL_BUFFER)
                case 0x5678:
                    memset(rx_local_buffer, 0x0, PCM_RX_RECV_BYTE);
                    bbpro_receive_pcm_data((short *)rx_local_buffer, PCM_RX_RECV_BYTE);

// tx/rx loop test
#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_BUFFER) && (AUDIO_PATH_SELECT != AUDIO_PATH_TX_RX_NORMAL)
                    if(memcmp(rx_local_buffer, tx_local_buffer, PCM_RX_RECV_BYTE) == 0) {
                        MODLOGE("check success");
                    } else {
                        MODLOGE("check failed");
                    }
#endif
                    break;
#endif
#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_FILE)
                case 0xabcd:
                    // check available free space
                    test_play_local_file_read();
                    break;
#endif
                default:
                    MODLOGD("unknown event id");
                    break;
            }
        }
    }
}

void test_pcm_tx_rx_start(void)
{
    MODLOGD("%s ++", __func__);

    tx_local_buffer = (uint8_t *)malloc(TX_LOCAL_BUFFER_SIZE);
    if(tx_local_buffer == NULL) {
        MODLOGE("malloc tx_local_buffer failed");
        ASSERT(0);
    }
    memset(tx_local_buffer, 0x0, TX_LOCAL_BUFFER_SIZE);

    rx_local_buffer = (uint8_t *)malloc(RX_LOCAL_BUFFER_SIZE);
    if(rx_local_buffer == NULL) {
        MODLOGE("malloc rx_local_buffer failed");
        ASSERT(0);
    }
    memset(rx_local_buffer, 0x0, RX_LOCAL_BUFFER_SIZE);

#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_FILE)
    test_play_local_file_start();
#endif

    if(test_pcm_tx_rx_task_handle == NULL) {
        test_pcm_tx_rx_task_handle = uos_create_task(test_pcm_tx_rx_task,
                                     0,
                                     TEST_PCM_TX_RX_TASK_MSGQ_SIZE,
                                     TEST_PCM_TX_RX_TASK_STACK_SIZE,
                                     TEST_PCM_TX_RX_TASK_PRIORITY,
                                     "txrx task");
        if(test_pcm_tx_rx_task_handle == NULL) {
            MODLOGE("create test_pcm_tx_rx_task_handle failed\n");
            ASSERT(0);
        }
    }

    MODLOGD("%s --", __func__);
}

void test_pcm_tx_rx_stop(void)
{
#if (AUDIO_TX_SELECT != AUDIO_TX_AUDIOHAL)
    test_stop_20ms_tx_timer();
#endif

#if (AUDIO_RX_SELECT == AUDIO_RX_LOCAL_BUFFER)
    test_stop_20ms_rx_timer();
#endif

#if (AUDIO_TX_SELECT == AUDIO_TX_LOCAL_FILE)
    test_play_local_file_stop();
#endif

    if(test_pcm_tx_rx_task_handle) {
        uos_delete_task((TASK_HANDLE *)test_pcm_tx_rx_task_handle);
        test_pcm_tx_rx_task_handle = NULL;
    }

    if(tx_local_buffer)
        free(tx_local_buffer);
    tx_local_buffer = NULL;

    if(rx_local_buffer)
        free(rx_local_buffer);
    rx_local_buffer = NULL;
}

#endif /* AUDIO_PLAY_NORMAL */

#endif/*USE_LV_BLUETOOTH*/

